package com.dwin.h5.app.services.mqtt;

import android.text.TextUtils;
import android.util.Log;

import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.persist.MqttDefaultFilePersistence;

/**
 * 管理mqtt的连接,发布,订阅,断开连接, 断开重连等操作
 *
 * @author LichFaker on 16/3/24.
 * @Email lichfaker@gmail.com
 */
public class MqttManagerV2 {
    private static final String TAG = "MqttManager";

    private static MqttManagerV2 mInstance = null; // 单例
    private MqttCallback mCallback; // 回调

    // Private instance variables
    public static MqttClient client;
    private static MqttConnectOptions conOpt;
    private boolean clean = true;

    // public String myTopicSender = ""; // 发送给设备的(多设备 改成h5返回给native)
    public String[] myTopicReceivers = null;
    public int[] qoss = null;
    private Integer qos = 0;
    private String clientId = "az";

    private MqttManagerV2() {
        mCallback = new MqttCallbackBus();
    }

    public static MqttManagerV2 getInstance() {
        if (null == mInstance) {
            mInstance = new MqttManagerV2();
        }
        return mInstance;
    }

    public static boolean mqttClientIsConnected() {
        return client.isConnected();
    }

    public static boolean reConnect() {
        boolean flag = false;
        if (null != client) {
            try {
                Log.d(TAG, "--**--reConnect to: " + client.getServerURI() + " with client ID " + client.getClientId());
                client.connect(conOpt);
                Log.d(TAG, "==**==reConnect to: " + client.getServerURI() + " with client ID " + client.getClientId());
                flag = true;
            } catch (Exception e) {
                String msg = e.toString();
                if (msg.contains("32100")) {
                    return true;
                }
                Log.d(TAG, "---**---reConnect failed for: ------" + e.toString());
                e.printStackTrace();
            }
        }
        return flag;
    }

    /**
     * 释放单例, 及其所引用的资源
     */
    public static void release() {
        try {
            if (mInstance != null) {
                mInstance.disConnect();
                mInstance = null;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 创建Mqtt 连接
     *
     * @param brokerUrl Mqtt服务器地址(tcp://xxxx:1863)
     * @param userName  用户名
     * @param password  密码
     * @param clientId  clientId
     * @return
     */
    public boolean creatConnect(String brokerUrl, String userName, String password, String clientId) {
        boolean flag = false;
        String tmpDir = System.getProperty("java.io.tmpdir");
        MqttDefaultFilePersistence dataStore = new MqttDefaultFilePersistence(tmpDir);
        try {
            // Construct the connection options object that contains connection parameters
            // such as cleanSession and LWT
            conOpt = new MqttConnectOptions();
            conOpt.setMqttVersion(MqttConnectOptions.MQTT_VERSION_3_1_1);
            conOpt.setCleanSession(clean);
            if (password != null) {
                conOpt.setPassword(password.toCharArray());
            }
            if (userName != null) {
                conOpt.setUserName(userName);
            }
            // Construct an MQTT blocking mode client
            client = new MqttClient(brokerUrl, clientId, dataStore);

            // Set this wrapper as the callback handler
            client.setCallback(mCallback);
            flag = doConnect();
        } catch (MqttException e) {
            e.printStackTrace();
            Log.d(TAG, "creatConnect: " + e.getMessage());
        }
        return flag;
    }

    // 订阅是个数组（可同时订阅多个主题），发送主题，需要发送的时候，h5传给app。
    public boolean creatConnect(String brokerUrl, String userName, String password, String[] topicReceivers, String deviceUniId) {
        this.myTopicReceivers = topicReceivers;
        qoss = new int[myTopicReceivers.length];
        for (int i = 0; i < myTopicReceivers.length; i++) {
            qoss[i] = qos;
        }
        for (int i = 0; i < topicReceivers.length; i++) {
            Log.d(TAG, i + "--topic->" + topicReceivers[i]);
        }

        boolean flag = false;
        String tmpDir = System.getProperty("java.io.tmpdir");
        MqttDefaultFilePersistence dataStore = new MqttDefaultFilePersistence(tmpDir);
        try {
            // Construct the connection options object that contains connection parameters
            // such as cleanSession and LWT
            conOpt = new MqttConnectOptions();
            conOpt.setMqttVersion(MqttConnectOptions.MQTT_VERSION_3_1_1);
            conOpt.setCleanSession(clean);
            conOpt.setAutomaticReconnect(true); // 设置是否自动重连
            conOpt.setKeepAliveInterval(10); // 设置“保持活动”间隔
            if (password != null) {
                conOpt.setPassword(password.toCharArray());
            }
            if (userName != null) {
                conOpt.setUserName(userName);
            }
            // Construct an MQTT blocking mode client
            // clientId必须唯一，否则会出现不能同时操作设备的问题  " timeStamp
            clientId = "cId" + System.currentTimeMillis() + deviceUniId;
            client = new MqttClient(brokerUrl, clientId, dataStore);
            // Set this wrapper as the callback handler
            client.setCallback(mCallback);

            flag = doConnect();
        } catch (MqttException e) {
            e.printStackTrace();
            Log.d(TAG, "creatConnect: " + e.getMessage());
        }
        return flag;
    }

    /**
     * 建立连接
     *
     * @return
     */
    public boolean doConnect() {
        boolean flag = false;
        if (client != null) {
            try {
                Log.d(TAG, "------doConnect to: " + client.getServerURI() + " with client ID " + client.getClientId());
                client.connect(conOpt);
                // Log.d(TAG, "======doConnect to: " + client.getServerURI() + " with client ID " + client.getClientId());
                flag = true;
            } catch (Exception e) {
                Log.d(TAG, "------Connect failed for: ------" + e.toString());
                e.printStackTrace();
            }
        }
        return flag;
    }


    public boolean publish(String myTopicSender, byte[] payload) {
        boolean flag = false;
        if (client != null && client.isConnected() && !TextUtils.isEmpty(myTopicSender)) {
            Log.d(TAG, "Publishing to topic \"" + myTopicSender + "\" qos " + qos + " " + new String(payload));
//            Logger.d("Publishing to topic \"" + topicName + "\" qos " + qos);
            // Create and configure a instruction
            MqttMessage message = new MqttMessage(payload);
            message.setQos(qos);
            // Send the instruction to the server, control is not returned until
            // it has been delivered to the server meeting the specified
            // quality of service.
            try {
                String json = myTopicReceivers[0]; // json 指令
                if (TextUtils.isEmpty(json)) {
                    return false;
                }
                client.publish(myTopicSender, message);
                flag = true;
            } catch (MqttException e) {
                e.printStackTrace();
            }
        }
        return flag;
    }


    public boolean subscribe() {
        boolean flag = false;
        if (client != null && client.isConnected()) {
            Log.d(TAG, "Subscribing to topic \"" + myTopicReceivers + "\" qoss " + qoss);
            if (qoss != null) {
                for (int i = 0; i < qoss.length; i++) {
                    qoss[i] = qos;
                    Log.d(TAG, "qos \"" + qoss[i]);
                }
            }
            try {
//                client.subscribe(myTopicReceivers, qoss);
                client.subscribe(myTopicReceivers);
                flag = true;
            } catch (MqttException e) {
                e.printStackTrace();
            }
        }
        return flag;
    }

    /**
     * 取消连接
     *
     * @throws MqttException
     */
    public void disConnect() throws MqttException {
        if (client != null && client.isConnected()) {
            for (int i = 0; i < myTopicReceivers.length; i++) {
                String topic = myTopicReceivers[i];
                if (!TextUtils.isEmpty(topic)) {
                    client.unsubscribe(topic);
                }
            }
            client.disconnect(1500);
            client.close();
        }
    }

}
